大家好: 我的前端项目是 React+es6+redux+webpack 结构
功能很简单,获取数据,渲染列表,问题在于,我把列表渲染完之后,需要调一个 bootgrid 的 jQuery 库,去生成分页和自定义操作的界面操作和效果,那么,在初次加载的时候,没有问题,但是在做 select 筛选的时候, componentDidMount 里面的没办法再次调用 bootgrid 的 jQuery 库,这样就导致了重新渲染的列表没办法展示其效果。我琢磨了很长时间,没找到解决办法。
请问各位,是否有办法解决这个问题??? 在线等!
简单代码如下:
class ClientsHistory extends Component {
constructor(props) {
super(props);
this.state = {list: []};
}
componentDidMount(){
let that = this;
$("#tb-grid-data").bootgrid();
let grid = $("#tb-grid-devicelist").bootgrid({
formatters:{
"operation":function(column , row){
return 'aaa';
}
}
});
}
changeSelect(sel_val){
this.setState({devicesn:sel_val});
// $("#tb-grid-devicelist").bootgrid('reload');
}
render(){
let devicelist = GetLocalData(device_data_key);
var rows = [];
if(devicelist != null){
var sn = this.state.devicesn;
devicelist.forEach(function(result, index){
if(typeof sn != 'undefined' && sn != ''){
if(result.sn == sn){
rows.push(
<ClientRows rowdata={result} key={index} />
);
}
}else{
rows.push(
<ClientRows rowdata={result} key={index} />
);
}
});
}
return(
<div className="card z-depth-1">
<div className="card-header">
<div className="div-tips-left">
<Select1 changeselect={this.changeSelect.bind(this)}/>
</div>
</div>
<div className="table-responsive">
<table id="tb-grid-devicelist" className="table table-striped">
<thead>
<tr>
<th data-column-id="sn">aa</th>
<th data-column-id="uptime">bb</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
</div>
);
}
}
1
bdbai 2016-08-24 13:36:20 +08:00 via Android
http://reactjs.cn/react/docs/component-specs.html
你可以自己把 bootgrid 封装成一个子组件,参数从 props 传进去。这样一旦父组件条件变化,子组件就能重新渲染。 |
2
simonlify OP @bdbai 你说的这种方法我试过了,好像不行的,父组件中 select 选择,触发事件,生成筛选参数,这时候,我只能把参数存到 state 中,这时候就会重新渲染 html 结构,在这之后才能调用 bootgrid 重新生成分页和操作标签,
问题在于,一旦调用 setState 后,最后的操作肯定是 render() 之后就不会有任何操作了,而我希望, render()之后,在调用 bootgrid ,刷新页面效果,不知道我说清楚了没? |
3
bdbai 2016-08-24 16:10:21 +08:00
@simonlify 子组件的 componentDidMount 和 componentDidUpdate 都要调用 bootgrid 。我简单改了一下子组件,你看这样如何。
https://gist.github.com/bdbai/2a195e83fc0fce13d2f9a6aa4d9dac5f |
4
ziki 2016-08-24 16:37:43 +08:00
componentDidMount 是只有首次渲染才执行的,那你试下 componentDidUpdate
|
5
Axighi 2016-08-24 16:45:21 +08:00
componentWillReceiveProps
|
6
simonlify OP @bdbai 你的代码,我没看到,不过我加了 componentDidUpdate ,不管用啊
@ziki 我加过了,没用 @Axighi componentWillReceiveProps 这个我也加过,没用, 我贴一下,我修改过的代码 , 我打过 alert , b 和 c 都不会执行, class Exam extends Component{ ....... componentDidMount(){ let grid = $("#tb-grid-devicelist").bootgrid({ formatters:{ "operation":function(column , row){ return 'aaa'; } } }).on("loaded.rs.jquery.bootgrid", function(){ grid.find(".devicelist-operation").on("change", function(e){ alert("You select on row: " + $(this).data("row-sn")); }); }); } componentDidUpdate(){ // this.refs.exam.onselect(); alert('b') let grid = $("#tb-grid-devicelist").bootgrid({ formatters:{ "operation":function(column , row){ return 'aaa'; } } }).on("loaded.rs.jquery.bootgrid", function(){ grid.find(".devicelist-operation").on("change", function(e){ alert("You select on row: " + $(this).data("row-sn")); }); }); } componentWillReceiveProps(){ alert('c') let grid = $("#tb-grid-devicelist").bootgrid({ formatters:{ "operation":function(column , row){ return 'aaa'; } } }).on("loaded.rs.jquery.bootgrid", function(){ grid.find(".devicelist-operation").on("change", function(e){ alert("You select on row: " + $(this).data("row-sn")); }); }); } changeSelect(obj, sel_val){ alert('a -- '+ sel_val) this.setState({devicesn:sel_val}); // $("#tb-grid-devicelist").bootgrid('reload'); } render(){ return( .......... ); } } |
7
Axighi 2016-08-24 17:13:37 +08:00
在 changeSelect 里的 setState 中加回调,应该可以。
|
8
Axighi 2016-08-24 17:15:11 +08:00
setState({}, () => { //do something})
|
9
bdbai 2016-08-24 17:17:42 +08:00
|
11
simonlify OP @bdbai 看过你的代码了,有些疑问,我的 render() 中有一个 select 的过滤条件:代码如下
<div className="card-header"> <div className="div-tips-left"> <Select1 changeselect={this.changeSelect.bind(this)}/> </div> <div className="div-clear"></div> </div> 我一般是触发 select 的时候,获取过滤条件,然后在 changeSelect()里面去 setState()条件,然后 render 你的代码中有个 shouldComponentUpdate 这个事件怎么触发?? |
12
simonlify OP |
13
serco 2016-08-24 18:18:29 +08:00
@simonlify 你一定哪里写错了,如果你的 changeSelect 确实执行了,肯定也会再执行到 componentDidUpdate. 你暂时可以不去管 shouldComponentUpdate ,那个只是控制 state 或者 props 改变时是否更新,默认是 true
|
14
bdbai 2016-08-24 19:34:02 +08:00 via Android
@simonlify 也许污染的 DNS 被缓存了。
子组件只关心需要显示哪些项目,由父组件从 props 传进去即可。过滤归别的组件( Select1 )管。 一旦父组件发现过滤条件有变,就会把新的筛选出的内容传递给子组件(调用 shouldComponentUpdate ),使子组件重新渲染(调用 componentDidUpdate )。如果 shouldComponentUpdate 发现实际过滤出来的东西没变,就直接返回 false 省去一次多余的渲染。 |
15
simonlify OP @serco 这段代码我反复检查了很多遍 ,不会有什么语法错误
changeSelect 如下: changeSelect(obj, sel_val){ alert('a -- '+ sel_val) this.setState({devicesn:sel_val}); } 这段代码执行后,下面就是 render() 然后就没有了,不会走到 componentDidUpdate 中去,我很郁闷!!! |
16
ianva 2016-08-24 20:38:57 +08:00
LZ 这个 render 逻辑写的真是,就这么简单的逻辑非要绕成看不懂
``` devicelist && devicelist.map((result,index)=> result.sn === sn ? <ClientRows rowdata={result} key={index} /> : null) ``` 之前设置个默认的 getInitialState devicesn 设 '',就完事了绕成这样 |
17
simonlify OP @bdbai 根据你的建议,我重新改了一下组件结构,父组件包括 Select 和 DeviceList 两个子组件
select 的值 以<DeviceList devicesn={ devicesn } /> 这种方式传入 如果在父组件中用 setState() 确实会重新渲染子组件,问题在于,不管用什么方式,都不会重新调用 bootgrid 也就是说,再次渲染子组件时, componentDidUpdate 是不会执行到的, 难道我漏掉了什么??? |
19
bdbai 2016-08-24 21:22:14 +08:00
|
20
arslion 2016-08-24 21:22:40 +08:00
是有多喜欢这个 bootgrid …
分页刷新查询选择吧啦吧啦,到底有多难写啊。你貌似已经在这个问题上纠结了一天多了,不如就此打住,延一天的时间自己写组件 对了,不是很懂这种感叹号的用法,一种微咆哮的感觉 ;) |
21
simonlify OP @arslion 这个问题确实是让我纠结半天多了,我之所以一直纠结这个问题,不是因为我没有别的解决办法,别的办法随便想想也有好几种。
只是本人刚做这种前端组件框架几个星期而已,很多原理方面的知识都不太清楚,如果碰到了这个问题,即使纠结这么长时间,也是搞清楚了蛮多别的问题,也算是避免以后再次踩类似这样的坑,不算没有收获 |
22
simonlify OP @bdbai 还是不麻烦你啦, shouldComponentUpdate 去掉我也试过,没有效果,也许是我还理解的不够深刻吧,不过还是搞明白了很多问题
这个问题呢,我想来想去,没必要再纠结下去了,我换了一种方式去解决了 大概的思路就是, select 获取过滤条件后,不用 setState 去重新渲染子组件列表,我从 bootgrid.js 源码里面下手,修改了一些源码,不管怎么说,这个刷选,我算是搞定了 不过这个问题的本质,确实是没有解决的,我现在项目时间比较急,只能等有空了再来研究这个问题了 谢谢各位耐心的解答,非常感谢! |
23
bdbai 2016-08-24 22:08:21 +08:00 via Android
@simonlify 最漂亮的方案是自己把 bootgrid.js 用 React 组件重写,然后开源...
|
25
simonlify OP @bdbai 哈哈,这个...这个... 目前暂不考虑, 分析 bootgrid 就够麻烦的了,还要组件重写,关键是我写 ReactJS ,不到一个月,完全没勇气完成这项壮举,还是等后来者吧。
|
26
simonguo 2016-09-03 11:37:03 +08:00
没有你这么做的,既然选择了用 react ,为什么还要用 bootgrid.js 去渲染 table ,建议你不要这样做。 推荐一个 react table 组件 http://rsuite.github.io/rsuite-table/
|
27
simonlify OP @simonguo 感谢,这个我也是后来才知道的,之所以用 bootgrid ,是因为这是我用 React 做的第一个项目,很多方面没有规范化,而且这个项目已经势成骑虎,不好在中途换了,也算是累积经验吧,下一个项目肯定不会再出现这种情况了,再次感谢!
|