预期行为:两个渲染。最初,您会看到一个加载程序,当在后台成功获取学生时,加载程序会更改为填充学生的列表。
我忽略了什么?
初始渲染
-
使用状态设置
elem
以显示(<Loader/>
(和students
数组(一个用于测试的初始对象( -
获取
students
useEffect
中的对象数组 -
获取更新状态成功时 - 将
students
设置为提取的数组,elem
设置为renderList
,这将用students
内容填充其列表项 -
console.log(students.length)
此时显示 1 - 正确 -
状态已更新,因此重新渲染
第二次渲染
console.log(students.length)
显示 49 -students
正确更新
为什么?- 7.renderList
看到students
的初始值(1 个对象(
是因为要显示elem
及其内容(students
(处于状态并且它们同时在useEffect
中更新吗?
<!-- language: lang-js -->
all imports
export default function AttendanceSingleClass(props) {
const {classId, groupId} = props.route.params.classObj;
const [students, _setStudents] = useState([{sId:1,name:'foo',fname:'bar'}]);
const [elem, _setElem] = useState(<Loader/>);
useEffect(() => {
async function _getStudentsList() {
try {
const students = await api.getStudentsList(groupId, classId);
_setStudents(students);
_setElem(renderList)
} catch (e) {
console.log(e)
}
}
_getStudentsList();
},[classId]);
const ListEl = (props) => {
return (
<View>..contents of list item...</View>
)
}
const renderList = () => {
return (
<View>
<FlatList
data={students}
extraData={students}
keyExtractor={item => item.sId}
renderItem={({item}) => <ListEl item={item} />}
/>
</View>
);
}
console.log(students.length);
return elem;
}
经过一些实验students
我尝试将数组作为prop
传递给renderList
- 工作。但我仍然不明白为什么它在全球范围内看到students
,而只看到初始值而不是更新状态(如上所示(。
<!-- language: lang-js -->
export default function AttendanceSingleClass(props) {
(...)
useEffect(() => {
async function _getStudentsList() {
try {
_setElem(renderList(students))
}
}
_getStudentsList();
}, [classId]);
const renderList = (students) => {
return (...);
}
(...);
}
我建议选择不同的方法。将组件或渲染函数存储在状态中感觉是一种不好的做法,同时已经知道何时渲染哪个。
例如,我喜欢使用这样的loading
状态:
export default function AttendanceSingleClass(props) {
const { classId, groupId } = props.route.params.classObj;
const [students, _setStudents] = useState([{ sId: 1, name: 'foo', fname: 'bar' }]);
const [loading, _setLoading] = useState(true);
useEffect(() => {
_setLoading(true);
async function _getStudentsList() {
try {
const students = await api.getStudentsList(groupId, classId);
_setStudents(students);
_setLoading(false);
} catch (e) {
console.log(e);
}
}
_getStudentsList();
}, [classId]);
const ListEl = (props) => {
return (
<View>..contents of list item...</View>
);
};
// early return the <Loader /> component when loading is true
if (loading) {
return <Loader />;
}
return (
<View>
<FlatList
data={students}
extraData={students}
keyExtractor={item => item.sId}
renderItem={({ item }) => <ListEl item={item} />}
/>
</View>
);
}