克隆JavaScript对象的最有效方法是什么?我已经看到obj = eval(uneval(o));被使用,但这是非标准的,只有Firefox支持.
我做过类似的事情,obj = JSON.parse(JSON.stringify(o));但质疑效率.
我也看到了具有各种缺陷的递归复制功能.
我很惊讶没有规范的解决方案.
我有一个外部(对组件),可观察的对象,我想听取更改.当对象更新时,它会发出更改事件,然后我想在检测到任何更改时重新呈现组件.
使用顶级React.render这是可能的,但在一个组件中它不起作用(这有一定意义,因为该render方法只返回一个对象).
这是一个代码示例:
export default class MyComponent extends React.Component {
handleButtonClick() {
this.render();
}
render() {
return (
<div>
{Math.random()}
<button onClick={this.handleButtonClick.bind(this)}>
Click me
</button>
</div>
)
}
}
Run Code Online (Sandbox Code Playgroud)
单击按钮会在内部调用this.render(),但这不是实际导致渲染发生的原因(您可以看到此操作因为创建的文本{Math.random()}不会更改).但是,如果我只是打电话this.setState()而不是this.render(),它可以正常工作.
所以我想我的问题是: React组件需要有状态才能重新渲染吗?有没有办法强制组件按需更新而不改变状态?
我想在state数组的末尾添加一个元素,这是正确的方法吗?
this.state.arrayvar.push(newelement);
this.setState({arrayvar:this.state.arrayvar});
Run Code Online (Sandbox Code Playgroud)
我担心原地修改阵列push可能会造成麻烦 - 这样安全吗?
制作阵列副本的替代方案,setState这看起来很浪费.
我有以下状态:
this.setState({ selected: { id: 1, name: 'Foobar' } });
Run Code Online (Sandbox Code Playgroud)
然后我更新状态:
this.setState({ selected: { name: 'Barfoo' }});
Run Code Online (Sandbox Code Playgroud)
由于setState被假定为合并,我希望它是:
{ selected: { id: 1, name: 'Barfoo' } };
Run Code Online (Sandbox Code Playgroud)
但相反它吃了id,状态是:
{ selected: { name: 'Barfoo' } };
Run Code Online (Sandbox Code Playgroud)
这是预期的行为,是什么解决方案只更新嵌套状态对象的一个属性?
我有一个问题,重新呈现状态会导致ui问题,并建议只更新我的reducer中的特定值,以减少页面上的重新呈现量.
这是我的州的例子
{
name: "some name",
subtitle: "some subtitle",
contents: [
{title: "some title", text: "some text"},
{title: "some other title", text: "some other text"}
]
}
Run Code Online (Sandbox Code Playgroud)
我目前正在更新它
case 'SOME_ACTION':
return { ...state, contents: action.payload }
Run Code Online (Sandbox Code Playgroud)
where action.payload是包含新值的整个数组.但是现在我实际上只需要更新内容数组中第二项的文本,这样的东西不起作用
case 'SOME_ACTION':
return { ...state, contents[1].text: action.payload }
Run Code Online (Sandbox Code Playgroud)
action.payload现在我需要更新的文本在哪里.
在reducer里面,给出一个状态对象:
var state = {
"data": [{
"subset": [{
"id": 1
}, {
"id": 2
}]
}, {
"subset": [{
"id": 10
}, {
"id": 11
}, {
"id": 12
}]
}]
}
Run Code Online (Sandbox Code Playgroud)
如您所见,数据是嵌套数组,每个元素都有数组.
知道action.indexToUpdate将是数据的索引,我想以编程方式将数据[action.indexToUpdate] .subset更新为新数组.例如,如果action.indexToUpdate = 0,则将更新data [0]
[{"id":1},{"id":2}]
Run Code Online (Sandbox Code Playgroud)
至
[{"id":4},{"id":5}]
Run Code Online (Sandbox Code Playgroud)
为了做到这一点,我有:
let newSubset = [{"id":4},{"id":5}]
let newState = update(state.data[action.indexToUpdate], {
subset: {
newSubset,
},
})
Run Code Online (Sandbox Code Playgroud)
但是当我执行此操作时,它会返回错误:
TypeError: value is undefined
Run Code Online (Sandbox Code Playgroud)
在更新功能上.
我一直在看这里的反应演绎:https://facebook.github.io/react/docs/update.html 但我真的无法弄清楚如何去做.请指教!
我一直在考虑使用React setState()方法更新这些嵌套属性的最佳方法是什么。我也愿意考虑更高效的方法来考虑性能,并避免与其他可能的并发状态更改发生冲突。
注意:我使用的是extends的类组件React.Component。如果您使用React.PureComponent,则在更新嵌套属性时必须格外小心,因为如果您不更改的任何顶级属性,这可能不会触发重新渲染state。这是说明此问题的沙箱:
CodeSandbox-组件vs PureComponent和嵌套状态更改
回到这个问题-我在这里关注的是性能以及setState()在状态上更新嵌套属性时其他并发调用之间可能存在的冲突:
例:
假设我正在构建一个表单组件,并且将使用以下对象初始化表单状态:
this.state = {
isSubmitting: false,
inputs: {
username: {
touched: false,
dirty: false,
valid: false,
invalid: false,
value: 'some_initial_value'
},
email: {
touched: false,
dirty: false,
valid: false,
invalid: false,
value: 'some_initial_value'
}
}
}
Run Code Online (Sandbox Code Playgroud)
根据我的研究,通过使用setState(),React将浅化合并传递给它的对象,这意味着它仅将检查顶级属性,在此示例中为isSubmittingand inputs。
因此,我们可以将包含这两个顶级属性(isSubmitting和inputs)的完整newState对象传递给它,也可以传递这些属性之一,并且这些属性将被浅层合并为先前的状态。
问题1
您是否同意最好的做法是仅传递state我们正在更新的顶级属性?例如,如果我们不更新该isSubmitting属性,则应避免将其传递给setState()其他属性,以避免与可能同时与该属性setState()一起排队的其他并发调用发生冲突/覆盖。它是否正确?
在此示例中,我们将仅传递具有inputs属性的对象。这样可以避免与其他setState() …
我想根据一个事件key/value在各自中嵌入一对新indexed array of objects的onChange.
但是,它已正确完成但在数组中添加了额外的元素.
原始对象数组:
0:{data: {…}}
1:{data: {…}}
2:{data: {…}}
3:{data: {…}}
4:{data: {…}}
Run Code Online (Sandbox Code Playgroud)
达到的结果:
0:{data: {…}}
1:{data: {…}}
2:{data: {…}, origin: "UK"}
3:{data: {…}, origin: "UK"}
4:{data: {…}}
5:"UK"
6:"UK"
Run Code Online (Sandbox Code Playgroud)
预期结果:
0:{data: {…}}
1:{data: {…}}
2:{data: {…}, origin: "UK"}
3:{data: {…}, origin: "UK"}
4:{data: {…}}
Run Code Online (Sandbox Code Playgroud)
下面是我在循环中执行的代码:
render: (rowData, indexes) => {
return (
<SelectField
id={`origin-${indexes.rowIndex}`}
defaultValue="US"
style={{ position: 'absolute' }}
onChange={text => {
this.setState(
{
generalPermitSelectedVehicles: [
...generalPermitSelectedVehicles,
(generalPermitSelectedVehicles[
indexes.rowIndex
].origin …Run Code Online (Sandbox Code Playgroud) 我对填充的对象/数组有一个反应状态,但后来我想编辑文本输入并编辑对象上的相关字段,到目前为止我还没有找到解决方案。
这就是我的状态:
const [data, setData] = useState({
working_hours: [
{
id: 1,
description: 'Random Text',
price: 100,
},
{
id: 2,
description: 'Text Random',
price: 100,
},
]
});
Run Code Online (Sandbox Code Playgroud)
这是我的 Jsx:
{data.working_hours.map(item =>
<>
<input type={text} value={item.description}
onChange={(e) => handleChange(e)} />
<input type={text} value={item.price}
onChange={(e) => handleChange(e)} />
</>
)}
Run Code Online (Sandbox Code Playgroud)
这是我尝试过的:
function handleChange(e){
const value = e.target.value;
setData({...data, [...data.working_hours, e.target.value]})
}
Run Code Online (Sandbox Code Playgroud) setState返回从钩子获取的(已更改的)先前状态useState似乎不会改变状态。运行以下直接代码片段
function App(){
const [state, setState] = React.useState([{x: 0}])
function changeCount(){
setState(prevState => {
console.log('before', prevState[0])
const newState = [...prevState]
newState[0].x += 1 //the shallow copy newState could potentially change state
console.log('after', prevState[0])//here x gets bigger as expected
return prevState //instead of newState we return the changed prevState
})
}
//checking state shows that x remained 0
return <div className='square' onClick={changeCount}>{state[0].x}</div>
}
ReactDOM.render(<App/>, document.getElementById('root'))Run Code Online (Sandbox Code Playgroud)
.square{
width: 100px;
height: 100px;
background: orange;
}Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div …Run Code Online (Sandbox Code Playgroud)我想将评论的键值更新为新值,同时保持其他键不变。我知道我可能需要展开运算符……但我不确定确切的语法。我需要在 setResource() 中放入什么来完成此操作?
const VideoPage = () => {
const [state, setResource] = useState(
{
video: 'placeholder'
loading: 'placeholder'
comment: 'placeholder'
}
)
const funct = () => {
setResource()
}
}
Run Code Online (Sandbox Code Playgroud) 我在理解为什么收到错误消息时遇到了一些麻烦:
类型错误:无法分配给对象“#”的只读属性“描述”
我知道原则是我不想在我的减速器中修改状态。相反,我想返回状态的新副本。
这是我的减速器:
action TOGGLE_CHECKBOX:
{
let copyOfItems = [...state.items]; // create a new array of items
copyOfItems.forEach(i => i.description = "newDescription");
// return a new copy of the state
return {
...state,
items: copyOfItems
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的 Reducer 测试:
it ('Test that each item description is set', () => {
const state = {
items: [
{ description: "d1" },
{ description: "d2" }
]
}
deepFreeze(state);
expect(MyReducer(state, { type: TOGGLE_CHECKBOX })).toEqual({
items: [
{ description: "newDescription" }, …Run Code Online (Sandbox Code Playgroud) 在我的反应应用程序中,我将父母的状态作为道具传递给孩子,如下所示:
<Child parentsState={...this.state} />
Run Code Online (Sandbox Code Playgroud)
它有效。但后来我想为什么不应该在没有扩展语法的情况下通过 this.state ,我确实喜欢:
<Child parentsState={this.state}
Run Code Online (Sandbox Code Playgroud)
它也起作用了。大多数情况下,我使用带有数组的扩展语法,我不知道没有扩展语法的对象和没有它的对象之间有区别吗?
谢谢你!
reactjs ×12
javascript ×9
redux ×3
ecmascript-6 ×2
object ×2
react-hooks ×2
react-redux ×2
state ×2
clone ×1
json ×1
react-jsx ×1