将新的商店状态放入道具后,反应不会重新渲染
Posted
技术标签:
【中文标题】将新的商店状态放入道具后,反应不会重新渲染【英文标题】:react doesn't get re-render after getting new store state into props 【发布时间】:2019-12-09 17:12:19 【问题描述】:我正在使用 react 和 react-redux。 我使用 mapstatetoprops 和 mapdispatchtoprops 来更新我的反应组件的视图。 除了 redux 存储更改后重新渲染不起作用外,一切正常。动作调度工作正常,reducer 工作正常,我可以 console.log 存储状态并检查差异。 起初,我使用了 useDispatch 和 useSelector,一切正常。但是我将其更改为 mapdispatchtoprops 和 mapstatetoprops 以将我的代码合并到我的项目队友的代码中。
我试图将 this.props.(whatineed) 直接放在我的 render() 组件的 return 中。据我了解,通过 mapstatetoprops,应该将存储状态传递到我的组件的 props 中。
import React, Component from 'react';
import ToggleButton, ToggleButtonGroup from 'react-bootstrap';
import useSelector, useDispatch from 'react-redux';
import checked, notchecked from '../../../actions';
import connect from "react-redux";
import local from './address';
import './index.css';
const mapStateToProps = state =>
return
localsel : state.selectedLocal.locals
let mapDispatchToProps = (dispatch) =>
return
check: (btn) => dispatch(checked(btn)),
uncheck: (btn) => dispatch(notchecked(btn))
class Seoul extends Component
constructor(props)
super(props)
render()
var btnclicked = (e) =>
let btnname = e.target.parentNode.getAttribute('id');
if (e.target.checked)
console.log('checked');
this.props.check(btnname);
;
if (!e.target.checked)
console.log('not checked');
this.props.uncheck(btnname);
;
// HERE IS WHERE I CAN CHECK THE PASSED STORE STATE
console.log(this.props.localsel);
// -------------------------------------------------
return (
<div className='localdiv localdiv1'>
// HERE IS WHERE I WANT TO SEE MY STORE STATE
this.props.localsel.map(val=>
return <h1>val</h1>
)
// --------------------------------------------
<ToggleButtonGroup className='togglebtngrp' type="checkbox">
<ToggleButton className='togglebtn0' onChange=btnclicked variant="outline-secondary" value=0 id="entireseoul">Entire Seoul</ToggleButton>
local.Seoul.map((value, index) =>
return (<ToggleButton key=index className='togglebtn' onChange=btnclicked variant="outline-primary" value=index + 1 id=value>value</ToggleButton>)
)
</ToggleButtonGroup>
</div>
);
export default connect(mapStateToProps, mapDispatchToProps)(Seoul);
该组件在父组件中导出,即
import React, Component from 'react';
import Jumbotron from 'react-bootstrap';
import Gyeongi, Incheon, Busan, Daegue, Daejeon, Sejong, Gwangju, Ulsan, Gangwon, Gyungnam, Gyungbuk, Jeonnam, Jeonbuk, Choongnam, Choongbuk, Jeju, Othercountry from './Locals';
import Seoul from './Locals';
import './Detailsrch.css';
class Detailsrch extends Component
render()
var localselect = (e) =>
let selector = document.getElementsByClassName('locals');
let selector_local = document.getElementsByClassName('localdiv');
let i = 0;
for (let j = 0; j < selector_local.length; j++)
selector_local[j].style.display = 'none';
let boxclass = e.target.getAttribute('name');
if (boxclass) document.getElementsByClassName(boxclass)[0].style.display = 'block';
while (selector[i])
selector[i].className = 'locals';
i++;
if (e.target.className == 'localtext')
e.target.parentElement.className = 'locals localclick';
else
e.target.className = 'locals localclick';
return (
<Jumbotron className='searchjumbo'>
<p>Locals</p>
<Seoul />
<Gyeongi />
<Incheon />
<Busan />
<Daegue />
<Daejeon />
<Sejong />
<Gwangju />
<Ulsan />
<Gangwon />
<Gyungnam />
<Gyungbuk />
<Jeonnam />
<Jeonbuk />
<Choongnam />
<Choongbuk />
<Jeju />
<Othercountry />
<hr className='firsthr' />
<p>type</p><hr />
<p>career</p><hr />
<p>country</p><hr />
<p>sex</p>
</Jumbotron>
);
;
export default Detailsrch;
这是我的减速器
import combineReducers from 'redux';
const initialstate =
locals: []
const localSelector = (state = initialstate, action) =>
switch(action.type)
case 'CHECKED':
if(action.payload)
var arr = state.locals;
arr.push(action.payload);
return
...state,
locals: arr
;
else
return state;
case 'NOTCHECKED':
if(action.payload)
var arrnum = state.locals.indexOf(action.payload);
var arr = state.locals;
arr.splice(arrnum, 1);
return
...state,
locals: arr
;
else
return state;
default:
return state;
;
const rootReducer = combineReducers(
selectedLocal: localSelector
);
export default rootReducer;
我希望当 props 值发生变化时,组件会重新渲染,我会在浏览器中看到变化。 props 值发生了变化,但在浏览器中没有任何反应。
【问题讨论】:
也发布你的减速器。 @ravibagul91 我在底部添加了它 【参考方案1】:我看不到 Detailsrch
在 Seoul
中导入,但反之亦然 Seoul
在 Detailsrch
中导入,根据代码和 cmets,我可以看到 this.props.localsel
正在发生变化,这在 @ 中使用987654326@ 所以会调用Seoul
的render 方法,由于Detailsrch
中没有this.props.localsel
的映射或使用,所以不会调用render 方法。
因此,如果您想重新渲染Detailsrch
,您需要将this.props.localsel
的映射从Seoul
更改为Detailsrch
,并将此值作为道具传递给Seoul
,它应该可以工作。
如果仍然存在问题,请将您的代码发布到 sandbox/codepen/jsfiddle,以便我们重现。
【讨论】:
是的,Seoul
是在Detailsrch
中导入的,我写错了。我想重新渲染Seoul
所以我把 this.props.localsel.map(val=>return val) 作为回报在渲染中,但它仍然没有工作。
请你把你的代码放在 jsfiddle/codepen 的某个地方,以便我们可以重现【参考方案2】:您可能正在遭受类似this 帖子提到的问题。使您的组件从存储中获取更改的一个技巧(当从存储中传递状态值作为道具时)是对道具(或您想要获取更改的道具)进行深度克隆,为此你可以使用 JSON:
JSON.parse(JSON.stringify(propToClone));
希望这会有所帮助。
P.S.:不要克隆作为函数的 props,因为 JSON 会擦除/忽略它们。
【讨论】:
【参考方案3】:你正在改变 redux 状态,如下所示
var arr = state.locals;
arr.push(action.payload);
redux 状态应该是不可变的。您可以在此处查看有关如何在 reducer 中更新 redux 存储的一些提示。
https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns
【讨论】:
我看了文档,我真的不明白。我在做顶层的浅拷贝吗?你能给我一个例子,我应该用什么来代替var arr = state.locals;
arr.push(action.payload);
return ...state, locals: arr ;
? ;(
当然,让我解释一下。假设您有这样的状态 locals: []
。如果您使用您的方法var arr = state.locals; arr.push('something');
,现在状态变为 locals: ['something']
。现在状态发生了变异。当您改变状态时,组件可能不知道状态已更改。您可以使用不可变的更新模式,例如 const newLocals = state.locals.slice(); newLocals.push(action.payload); return ...state, locals: newlocals
非常感谢!最后我明白了。如果我使用var arr = state.locals;
,那么 arr 将成为 state.locals 的引用变量,因为它们是数组!以上是关于将新的商店状态放入道具后,反应不会重新渲染的主要内容,如果未能解决你的问题,请参考以下文章
防止子级在更新父级状态时重新渲染,使用父级方法作为本机反应的道具