React组件传值与排序:props转state是否为引用传递及最佳实践
React组件数据传递与排序问题解答
问题1:是否是按引用传递机制导致的?
是的,这完全是JavaScript引用类型的特性导致的:
- JavaScript里数组属于引用类型,当你把父组件的
userList传给Table组件的data,再通过setCache(data)把data赋值给cache时,cache和userList指向的是内存中同一个数组对象。 - 另外
Array.sort()是原地排序方法,会直接修改调用它的数组本身,所以当你在sortOrder里对cache执行排序时,本质上是修改了那个共享的数组,父组件的userList自然也会跟着变化。
问题2:应该采用哪种方式?
绝对不能继续用当前的方式,推荐让渲染函数使用cache数据,原因和调整方案如下:
- 当前写法违反了React的单向数据流原则:子组件意外修改了父组件的状态数据,会导致数据流向混乱,后续调试和维护会非常困难。
- 正确的做法:
- 首先在Table组件接收
data时,做一次浅拷贝再存入cache,切断和父组件数组的引用关联:useEffect(()=>{ if(data){ setCache([...data]) // 用展开运算符做浅拷贝 } },[data]) - 修改渲染逻辑,让表格主体基于
cache数据渲染。可以选择两种方案:- 方案一:修改父组件的
renderBody为接收数据的函数,Table组件调用时传入cache:// 父组件User function User(){ const [userList, setUserList] = useState([]) // fetch and update userList... function renderBody(data){ return data.map(user=> <tr> <td>{user.name}</td> </tr> ) } return <Table data={userList} renderBody={renderBody} /> } // Table组件 function Table({data, renderBody}){ const [cache, setCache] = useState([]) useEffect(()=>{ if(data){ setCache([...data]) } },[data]) function sortOrder(){ const sorted = [...cache].sort((x, y) => String(x[id]).localeCompare(y[id], 'en', { numeric: true })) setCache(sorted) } return <table>{renderBody(cache)}</table> } - 方案二:Table组件内部处理渲染逻辑,无需父组件传
renderBody,逻辑更内聚:// Table组件 function Table({data}){ const [cache, setCache] = useState([]) useEffect(()=>{ if(data){ setCache([...data]) } },[data]) function sortOrder(){ const sorted = [...cache].sort((x, y) => String(x[id]).localeCompare(y[id], 'en', { numeric: true })) setCache(sorted) } return ( <table> {cache.map(user=> <tr> <td>{user.name}</td> </tr> )} </table> ) }
- 方案一:修改父组件的
- 额外注意:排序时最好先拷贝原数组再排序(比如
[...cache].sort(...)),避免原地修改cache的当前状态,符合React状态更新的不可变原则。
- 首先在Table组件接收
内容的提问来源于stack exchange,提问作者Carter
相关产品推荐
相关产品推荐

