Skip to main content

useState

react 是基于数据是不可变的(每次 setState 都会返回一个新数据),这也是为什么需要 setState()来更新数据而不能使用像 vue 的 this.state = newState 的形式更新数据的原因,其实你用 this.state=newState 确实可以改数据,但是 react 不知道数据变了。

setState 的写法可以分为两类

setState(updater, [callback])

第一个参数是一个 updater 函数;第二个参数是个回调函数(可选)

修改开关状态变量经常会用 updater 来改变状态,例如:

this.setState((state) => ({
isToggleOn: !state.isToggleOn,
}));

setState(stateChange, [callback])

第一个参数是一个对象;第二个参数是个回调函数(可选)

this.setState({ number: 2 });

注意: setState()不是立刻更新组件。其可能是批处理或推迟更新。这使得在调用 setState()后立刻读取 this.state 的一个潜在陷阱。

state 的赋值

通常情况下的赋值

适用的类型有:数字,字符串,布尔值,null, undefined。示例如下:

this.setState({
count: 1,
title: "React",
success: true,
});

数组类型的赋值

  1. 如有一个数组类型的状态 books,当向 books 中增加一本书时,使用数组的 concat 方法或 ES6 的数组扩展语法(spread syntax)
var books = this.state.books;
// 方法一:将state先赋值给另外的变量,然后使用concat创建新数组
this.setState({
books: books.concat(['三体']);
})

// 方法二:使用state、concat创建新数组
this.setState(state => ({
books: state.books.concat(['三体']);
}))

// 方法三:ES6数组扩展 spread syntax
this.setState(state => ({
books: [...state.books, '三体'];
}))
  1. 当从 books 中截取部分元素作为新状态时,使用数组的 slice 方法:(利用 splice 返回的数组也是同理)
var books = this.state.books;
// 方法一:将state先赋值给另外的变量,然后使用slice创建新数组
this.setState({
books: books.slice(1,3);
})

// 方法二:使用state、slice创建新数组
this.setState(state => ({
books: state.books.slice(1,3);
}))
  1. 当从 books 中过滤部分元素后,作为新状态时,使用数组的 filter 方法:
var books = this.state.books;
// 方法一:将state先赋值给另外的变量,然后使用filter创建新数组
this.setState({
books: books.filter(item => {
return item != '三体';
});
})

// 方法二:使用state、filter创建新数组
this.setState(state => ({
books: state.books.filter(item => {
return item != '三体';
});
}))

对象类型的赋值

  1. 使用 ES6 的 Object.assgin 方法
var owner = this.state.owner;
// 方法一:将state先赋值给另外的变量,然后使用Object.assign创建新对象
this.setState({
owner: Object.assign({}, owner, {name: 'Jason'});
})

// 方法二:使用state、Object.assign创建新对象
this.setState(state => ({
owner: Object.assign({}, state.owner, {name: 'Jason'});
}))
  1. 使用对象扩展语法(object spread properties)
var owner = this.state.owner;
// 方法一:将state先赋值给另外的变量,然后使用对象扩展语法创建新对象
this.setState({
owner: {...owner, name: 'Jason'};
})

// 方法二:使用state、对象扩展语法创建新对象
this.setState(state => ({
owner: {...state.owner, name: 'Jason'};
}))

注意

与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。你可以用函数式的 setState 结合展开运算符来达到合并更新对象的效果。

const [state, setState] = useState({});
setState((prevState) => {
// 也可以使用 Object.assign
return { ...prevState, ...updatedValues };
});

惰性初始 state

initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用:

const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});

链接

FQ