本文小编为大家详细介绍“vue和react中props变化后怎么修改state”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue和react中props变化后怎么修改state”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
如果只想在 state 更改时重新计算某些数据,比如搜索框案例。
vue
<template> <div> <input type="text" v-model="filterText"> <ul> <li v-for="item in filteredList" :key="item.id"> {{ item.text }} </li> </ul> </div> </template>
<script> export default { props: { list: { type: Array, default: () => ([]) } }, data () { return { filterText: '' } }, computed: { filteredList () { return this.list.filter(item => item.text.includes(this.filterText)) } } } </script>
react
import React, { PureComponent } from 'react'; class Example extends PureComponent { state = { filterText: '' }; handleChange = event => { this.setState({ filterText: event.target.value }) } render() { const filteredList = this.filter(this.props.list, this.state.filterText) return ( <> <input type="text" onChange={this.handleChange} value={this.state.filterText} /> <ul> { filteredList.map( item => <li key={item.id}>{item.text}</li> ) } </ul> </> ); } }
如果你想在 prop 更改时“重置”某些 state,比如随机默认值案例
vue
Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动:侦听属性 watch。
<template> <div> <input type="text" v-model="text"> </div> </template>
<script> export default { props: { email: { type: String, default: '' } }, data () { return { text: '' } }, watch: { email: { immediate: true, handler (value) { this.text = value } } } } </script>
react
React生命周期 getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
父组件重新渲染时触发,请注意,不管原因是什么,都会在每次渲染前触发此方法。
class Example extends Component { state = { text: '' }; handleChange = (event) => { this.setState({ text: event.target.value }) } static getDerivedStateFromProps(nextProps, prevState) { if (prevState.email !== nextProps.email) { return { text: nextProps.email, email: nextProps.email } } return {text: prevState.text} } render() { return ( <> <input type="text" onChange={this.handleChange} value={this.state.text} /> </> ); } }
直接复制 prop 到 state 是一个非常糟糕的想法。这两者的关键在于,任何数据,都要保证只有一个数据来源,而且避免直接复制它。
vue
<template> <div> <input type="text" :value="value" @input="handleInput"> </div> </template>
<script> export default { props: { value: { type: String, default: '' } }, methods: { handleInput (e) { this.$emit('input', e.target.value) } } } </script>
<template> <div id="app"> <Example v-model="email"/> <button @click="handleClick">默认值</button> </div> </template>
<script> import Example from './components/Example.vue' export default { components: { Example }, data () { return { email: '' } }, methods: { handleClick () { this.email = String(Math.random()) } } } </script>
react
function Example (props) { return <input onChange={props.onChange} value={props.email} />; }
class App extends React.Component { state = { email: '' } handleClick = () => { this.setState({ email: String(Math.random()) }) } handleChange = (event) => { this.setState({ email: event.target.value }) } render() { return ( <> <Example email={this.state.email} onChange={this.handleChange} /> <div> <button onClick={this.handleClick}>默认值</button> </div> </> ); } }
react可以通过this.state.xx的方式直接获取state,但是当我们修改state的时候,往往有许多的坑。
组件修改state,并不会重新触发render。例如:
//错误 this.state.title='attend'; //正确 this.setState({title:'attend'});
调用setState时,组件state并不会立即改变,只是把要修改的状态放入事件队列当中,为了弥补这个问题,使用另一种 setState() 的形式,接受一个函数。
这个函数将接收前一个状态作为第一个参数,应用更新时的 props 作为第二个参数,代码如下:
//正确 this.setState((prevState, props)=>({ counter: prevState.counter + 1 }))
当调用setState()修改组件的状态时,只需要传入发生改变的state,而不是完整的state,因为组件state的更新是一个合并的过程:
this.state = { title: 'React', content: 'React is an wondeful JS library' }
当只需要修改title时,只需要将修改的title传给setState即可:
this.setState({title:'ReactJs'});
react会合并最新的title到原来的状态,同时保留原来状态的content,最终合并state为:
this.state = { title: 'ReactJs', content: 'React is an wondeful Js library' }
react官方把state当成不可变对象,一方面直接修改this.state,组件并不会重新render;另一方面,state中包含的所有状态都应该是不可变的对象,state当中的某一个状态发生变化时,应该重新创建这个状态对象,而不是直接修改原来的state状态,那么当状态发生变化时,如何去创建新的状态呢,我们根据状态类型可以分为下面三种情况:
状态类型为不可变类型
number、string、boolean、null、undefined
这种情况最简单,因为状态是不可变类型,所以直接给要修改的状态赋一个新值即可,例如我们要修改的count为number型,title(string),success(boolean)三个状态:
this.setState({ count:1, title:'React', success:true })
状态类型为数组
假如有一个数组类型的状态books,当向books中增加一本书时。
//方法一:使用preState,concat创建新数组 this.setState((prevState)=>({ books: prevState.books.concat(['React Guide']) })) //方法二:ES6 spread syntax this.setState(prevState=>({ books:[...prevState,'React Guide'] }))
当我们从books中截取部分元素作为新状态时,可以用数组的slice方法:
this.setState(prevState=>({ books: prevState.books.slice(1,3); }))
当从books中过滤部分元素后,作为新状态时,可以使用filter方法:
this.setState(prevState=>({ books: prevState.books.filter(item=>{ return item!='React'; }) }))
【注意】不要使用push,pop,shift,unshift,splice等方法修改数组类型的状态,因为这些方法都是在原数组的基础上修改的,而concat,slice,filter会返回一个新的数组。
状态的类型是普通对象
(1) 使用es6的Object.assgin()方法
this.setState({ onwer: Object.assgin({},preState.onwer,{name:'Jason'}); })
(2) 使用对象扩展语法(Object spread properties):
this.setState(preState=>{ owner: {...preState.owner, name:'Jason'} })
总结
创建新的状态的关键是避免使用直接修改原对象的方法,这种方法在vue中称为变异方法,而是使用可以返回一个新对象的方法,当然可以使用Immutable的JS库(Immutable.js)实现类似的效果。
思考
为什么React推荐组件状态的修改是不可变对象呢?
(1) 不可变对象的修改会返回一个新的对象,不用担心原对象在不小心的情况下修改导致的错误,方便程序的管理和调试。
(2) 处于性能的考虑,对象组件的状态是不可变对象时,在组件的shouldComponentUpdate方法中仅需要比较前后两次状态对象的引用就可以判断状态是否真的改变,从而避免不必要的render调用。
进阶
除了以上方法改变react组件的状态之外,我们还经常会用到replaceState()改变组件的状态。
replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。
//使用语法: replaceState(object nextState[, function callback])
nextState
,将要设置的新状态,该状态会替换当前的state。
callback
,可选参数,回调函数。该函数会在replaceState设置成功,且组件重新渲染后调用。
读到这里,这篇“vue和react中props变化后怎么修改state”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。