Reactjs React/Context-API/TypeScript:如何初始化web应用程序并避免UI在statup上闪烁?
当用户导航到我的网站时,我需要按如下方式初始化React web app:Reactjs React/Context-API/TypeScript:如何初始化web应用程序并避免UI在statup上闪烁?,reactjs,typescript,context-api,Reactjs,Typescript,Context Api,当用户导航到我的网站时,我需要按如下方式初始化React web app: 如果传入用户从未请求过web应用,我想将UI语言设置为浏览器默认值(navigator.language) 如果传入用户已经访问了站点并选择了首选语言(存储在localStorage中的lang),我想用这种语言初始化UI 如果传入用户有一个帐户并且已经连接(localStorage中有可用的令牌),我想自动连接他并相应地呈现应用程序:登录按钮转换为欢迎消息,UI语言设置为用户首选项 为此,我使用React上下文A
defaultUser
对象
defaultUser
:初始化默认用户
const defaultUser={
语言:“en_en”,
断开连接:错误
}
上下文
:创建默认上下文
export const AppContext=createContext({
connectedUser:defaultUser,
})
提供程序
:使用默认上下文创建提供程序
导出函数AppProvider({children}:any){
[...]
常量提供程序={
连接器
}
返回(
我找到了一种解决方案,只需对
加载设置条件,将其推迟到序列的末尾。然而,我现在没有闪烁,而是出现了延迟和其他不必要的副作用
目标是在React-Act呈现之前和Window
可用之后改变所有序列。然后动态创建上下文,然后呈现全部
我认为,如果我可以在Appconstructor()
期间动态创建AppContext并将变量传递给createContext()
,或者可能是componentWillMount()
(不确定窗口何时可用),这一点就会得到解决,但是TypeScript开始处理类型问题,我仍然被卡住了。您没有共享初始化上下文的代码,但我怀疑您将默认值设置为硬编码值或navigator.language
并因此体验到闪烁。我想建议两种方法来解决此问题:
解决方案1
也许您可以通过访问localStorage.get('lang')以编程方式生成默认上下文,而不是使用硬编码的默认上下文虽然这个解决方案有一个小小的缺点:你会把反应和浏览器的关系混合在一起,但是我认为在这种情况下,它是一个可供选择的替代品,因为它对读者来说是非常简单和明显的。
解决方案2
或者,在调用ReactDOM.render
时,可以将localStorage
中所需的任何内容作为道具传递给应用程序,因此可以将与浏览器相关的逻辑与纯React内容分开
我希望这是有意义的。以下是我的后续行动,以防对其他人有所帮助
带函数的Init上下文
我没有用硬编码的值初始化defaultUser
,以后再更新它,而是按照建议使用返回navigator.lang
的函数直接设置它。这解决了UI标签上的闪烁问题
在RectDOM.render之前初始化数据
然而,我仍然在UI组件上闪烁,我必须从API调用中获取相应的状态
例如,如果传入用户在localStorage
中存储了有效的会话令牌,则必须禁用登录按钮。在执行此操作之前,我需要通过对API的异步调用确保会话令牌有效。我没有找到一种方法让上下文初始化将其«等待»,它似乎是同步的
这就是Amit第二个建议发挥作用的地方。我没有在React中费力地找到解决方案,而是在React之前做了必要的处理React dom.render
,然后将东西作为道具传递给
这对于获取和传递数据非常有效
除了上下文API在其任何数据从上下文外部引用对象时不再setState
。换句话说,使用函数调用可以初始化(可能通过val),但对外部对象的引用会中断setState
结论
由于我的项目仍处于早期阶段,这让我有机会摆脱上下文API,根据需要进行适当的初始化,并使用基本React对props/State progagation进行编码。你好,Amit,谢谢。这显然是有意义的,并帮了我很多思维重置。最终导致摆脱上下文API。有关更多详细信息,请参阅下面的答案s
export class AppContainer extends Component {
static contextType = AppContext
componentDidMount() {
/** If user is not connected, verify if a stored session exists and use it to connect user */
if (!this.context.connectedUser.isConnected) {
[...do things...]
}
}