NextJs 在调整大小时传递动态宽度而不是重新渲染

Fac*_*eri 2 javascript css reactjs next.js react-hooks

我正在尝试将宽度动态传递给组件的样式。在第一次加载时,没关系,但是如果我调整大小,它永远不会重新呈现组件,即使钩子正在工作。

我读到了,因为 NextJs 是服务器端渲染,这可能会导致这个客户端的问题。所以这是代码:

const useWidth = () => {
  if (process.browser) {
    const [width, setWidth] = useState(window.innerWidth);
    const handleResize = () => setWidth(window.innerWidth);
    useEffect(() => {
      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }, [width]);
    return width;
  }
  return 0;
};
Run Code Online (Sandbox Code Playgroud)

组件(减少只是为了显示示例)

const Login = () => {
  const windowWidth = useWidth();
  const width = windowWidth > CELLPHONE_WIDTH ? '36.6rem' : '90%';
  const loginStyles = styles(width);
  return (
    <div className='container'>
      <TextInput
        type='text'
        width={width}
        placeholder='Email'
      />
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)

样式

function textInputStyles(width) {
  return css`
    width: ${width};
  `;
}

export default textInputStyles;
Run Code Online (Sandbox Code Playgroud)

Has*_*qir 6

这里的问题是代码首先使用 Next.js 在服务器端运行。因为 process.browser 在服务器端返回 false,所以你的钩子逻辑永远不会被注册。仅返回 0。由于没有注册钩子并且没有设置事件,改变窗口大小不会触发重新渲染。

您需要使用 componentDidMount() 或 useEffect。

这是一个适用于您的案例的示例。

const useWidth = () => {
    const [width, setWidth] = useState(0); // default width, detect on server.
    const handleResize = () => setWidth(window.innerWidth);
    useEffect(() => {
      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }, [handleResize]);
    return width;
};
Run Code Online (Sandbox Code Playgroud)

另一方面,如果您想确保您的初始状态是浏览器窗口的状态,您只能在客户端动态加载您的组件。

import dynamic from 'next/dynamic'
const Login = dynamic(
  () => import('./pathToLogin/Login'),
  { ssr: false },
)
Run Code Online (Sandbox Code Playgroud)

并在使用 Login 的组件中。

const TopLevelComponent = () => {
 <Login {...props} />
}
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的 Login 组件中自由使用 window 对象。

const useWidth = () => {
  // Use window object freely
  const [width, setWidth] = useState(window.innerWidth); // default width, detect on server.
Run Code Online (Sandbox Code Playgroud)

请参阅是否仍然存在混乱。