Javascript 在渲染之前,真的需要一些帮助来弄清楚componentWillMount()的逻辑吗

Javascript 在渲染之前,真的需要一些帮助来弄清楚componentWillMount()的逻辑吗,javascript,reactjs,axios,Javascript,Reactjs,Axios,这可能是一种长期阅读,我已经阅读和尝试了这么多的解决方案,但没有成功!基本上我有三个MySQL表,一个是用户列表,另一个是文件数据列表。它们与第三个表配对,该表有一列表示用户id,一列表示文件id 当用户登录到应用程序时,它会从表1中获取其ID,转到表3,查找与其用户ID位于同一行的所有文件ID,然后从表2中返回文件信息。基本上是直截了当的,但事实并非如此 我当前的代码: componentWillMount() { this.getClientFiles(); } 这要求: getC

这可能是一种长期阅读,我已经阅读和尝试了这么多的解决方案,但没有成功!基本上我有三个MySQL表,一个是用户列表,另一个是文件数据列表。它们与第三个表配对,该表有一列表示用户id,一列表示文件id

当用户登录到应用程序时,它会从表1中获取其ID,转到表3,查找与其用户ID位于同一行的所有文件ID,然后从表2中返回文件信息。基本上是直截了当的,但事实并非如此

我当前的代码:

componentWillMount() {
    this.getClientFiles();
}
这要求:

getClientFiles() {
        let id = this.props.currentUser.user_id;
        let file_refs = [];

        axios.get(`/users/get-client-files/${id}`)
          .then(res => {
            let response = res.data.response;

            for (let i = 0; i < response.length; i++) {
                file_refs.push(response[i].file_id);
            }
            this.setState({
                file_refs
            });
            this.getFileData();
        });
    }
在这里,函数循环遍历处于状态的fileRefs,对每个引用ID进行调用,并将其返回到fileData并将其保存到状态

问题是。。。。在登录后加载第一页时,文件不会呈现。如果你点击cmd+R刷新,它们就在那里。我了解承诺链和JS函数的异步性质,我了解
componentWillMount()
应该在安装组件之前运行,并且
setState
应该触发组件的重新呈现

我尝试过的事情: 1) 在
返回(
)之前的
渲染()之后添加以下代码:

当函数在返回的_数据的状态设置为true之前异步运行时,结果是呈现闪烁,其中4-5个呈现

2) 将
setState({returned_data:true})
移动到
getClientFiles()函数中。这只是提前结束渲染,在刷新页面之前不会生成任何文件

3) 将
componentWillMount()
换成
componentDidMount()

显然,函数链和React的内置方法中有一个基本方面我没有

有人能帮忙吗

编辑#1 问题似乎是在第一次渲染时,
let id=this.props.currentUser.user\u id
未定义的
,因此
getClientFiles
中的调用实际上是要
/users/get client files/undefined

编辑#2-由@devserkan请求 我希望这就是你想要的:)

第一批
get client files/${id}
:返回空数组
/get file/“+fileRefs[i]
:不运行

第二次加载:
get client files/${id}
:返回包含5项的数组
/get file/“+fileRefs[i]
:根据每个文件的详细信息适当运行5次

很明显,问题在于,
get client files/${id}
没有得到任何东西,因为它没有从中搜索的
${id}
。ID是通过道具传递的,但似乎不能立即使用

编辑#3 下面是获取ID并将其设置为state的函数

getUser = () => {
    let localToken = localStorage.getItem("iod_tkn");

    axios({
        url: "/admins/current",
        method: "get",
        headers: {
            Authorization: localToken
        }
    })
        .then(result => {
            this.setState({
                isLoggedIn: true,
                user: result.data,
                user_id: result.data.user_id
            });
        })
        .catch(err => {
            this.setState({ isLoggedIn: false });
            console.log(err);
        });
};
和App.js呈现以下内容:

render() {
    const { loading } = this.state;

    if (loading) {
        return <Spinner />;
    }

    return (
            <AdminProvider>
                <FileProvider>
                    <Provider>
                        <Appbar isLoggedIn={this.state.isLoggedIn} logout={this.logout} />
                        <Main
                            getUser={this.getUser}
                            isLoggedIn={this.state.isLoggedIn}
                            currentUser={this.state.user}
                        />
                        <BottomNav />
                    </Provider>
                </FileProvider>
            </AdminProvider>

    );
}
render(){
const{loading}=this.state;
如果(装载){
返回;
}
返回(
);
}

因此,通过将
this.state.user
传递到Main.js中,该组件应该在收到道具后重新呈现,对吗

我认为您的代码结构有问题
setState
是一个异步函数,它将回调作为第二个参数。你应该利用它的优势。您可以在setState完成后执行函数,并使用第二个参数回调(更新程序函数)使用更新的状态,如:

已编辑第二个选项不应设置state
file_refs
,除非在渲染方法中使用它。 试试这个:

axios.get(`/users/get-client-files/${id}`)
      .then(res => {
        let response = res.data.response;

        for (let i = 0; i < response.length; i++) {
            file_refs.push(response[i].file_id);
        }
        this.getFileData(file_refs);
    });

getFileData(file_refs) {
    let fileRefs = file_refs;
    let fileData = [];
    // rest of your code
}
axios.get(`/users/get client files/${id}`)
。然后(res=>{
让响应=res.data.response;
for(设i=0;i

如果问题仍然存在,请告诉我。很乐意提供帮助

问题在于,在
componentWillMount()
中,异步调用可能无法在呈现装载阶段之前及时检索结果,因此会产生意外的副作用。很可能组件将使用空数据进行渲染。 从异步调用呈现数据的最佳位置是
componentDidMount()


作为补充说明,从16.3版开始,
componentWillMount()
被认为是生命周期中不安全的方法,在未来的版本中将被删除,因此您最好不要再使用它。

因为您的
用户id
来自异步作业,所以您应该执行条件渲染。比如:

{ user_id && <ClientDashboard user_id={user_id} ... /> }
{user\u id&&}
另外,你还可以稍微整理一下你的代码:)我在这里模仿你的应用程序

const用户文件=[
{文件id:1,客户端名称:“foo”},
{文件id:2,客户端名称:“bar”},
{文件id:3,客户端名称:“baz”},
];
常量文件=[
{文件id:1,名称:“fizz”,大小:10},
{文件id:2,名称:“buzz”,大小:20},
{文件id:3,名称:“fuzz”,大小:30},
];
const fakeRequest=()=>新承诺(解析=>
setTimeout(()=>解析(用户文件),1000)
);
const fakeRequest2=id=>新承诺(解析=>{
const file=files.find(el=>id==el.file\u id);
setTimeout(()=>解析(文件),1000)
}
);
类应用程序扩展了React.Component{
状态={
文件参考文献:[],
客户端文件:[],
返回的数据:false,
}
componentDidMount(){
此文件为.getClientFiles();
}
getClientFiles(){
伪造
。然后(res=>{
const file_refs=res.map(el=>el.file_id);
这是我的国家({
文件参考
});
这是.getFileData();
});
}
获取文件
this.setState({
    file_refs
}, () => {
    this.getFileData();
});
axios.get(`/users/get-client-files/${id}`)
      .then(res => {
        let response = res.data.response;

        for (let i = 0; i < response.length; i++) {
            file_refs.push(response[i].file_id);
        }
        this.getFileData(file_refs);
    });

getFileData(file_refs) {
    let fileRefs = file_refs;
    let fileData = [];
    // rest of your code
}
{ user_id && <ClientDashboard user_id={user_id} ... /> }