Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

阿里面试(day6) #19

Open
robbiemie opened this issue Mar 9, 2024 · 3 comments
Open

阿里面试(day6) #19

robbiemie opened this issue Mar 9, 2024 · 3 comments

Comments

@robbiemie
Copy link
Owner

robbiemie commented Mar 9, 2024

题目

  1. 解读程序,写处console.log打印出来的内容
let i = 0;

const Test = () => {
  
  const [count, setCount] = useState(0);


  useEffect(() => {
    
    setInterval(() => {
      setCount(count+1);
    }, 1000);
    
  }, []);
  

  console.log(`${++i} - ${count}`);


  return <span>{`${i} - ${count}`}</span>;
};

//请在此处写出console.log输出的内容
  1. 一个列表组件,其内部拥有state,内容为一个数组,当往数据的开头位置插入一条数据,父子组件将会发生什么
  2. 编程题
/*
 * 编写一个 名为 Message 的 react 弹窗提示组件, 要求
 *  1. 用 Flex 布局 + rem 实现弹窗样式,弹窗大小 400*300 , 垂直水平居中,背景蒙层黑色透明度 30%	
 *  2. 可以将给定的提示文案中的占位符替换成按钮组件``` <Button /> ```并展示,假设数据已由接口返回,
 * 	通过 props 传入, 且数据结构为: 
 * ```JSON
	 {
     tips: "操作成功!你可以 {$2} 或者 {$1}.",
     buttons:[{
       "text": "重试"
    	 },{
       "text": "退出"
      }, {
       "text": "继续"
     }]
   }
 *```
 * 3. 可以将props 传入的数据被转化成相应的 UI, 如上面的数据结构会被转换成 	

 * ```jsx
 * <div>操作成功!你可以<Button text="继续" />或者<Button text="退出" /></div>
 * ```
 */
@robbiemie
Copy link
Owner Author

robbiemie commented Mar 9, 2024

Q: 解读程序,写处console.log打印出来的内容

let i = 0;

const Test = () => {
  
  const [count, setCount] = useState(0);


  useEffect(() => {
    
    setInterval(() => {
      setCount(count+1);
    }, 1000);
    
  }, []);
  

  console.log(`${++i} - ${count}`);


  return <span>{`${i} - ${count}`}</span>;
};

//请在此处写出console.log输出的内容

A: 答案如图:

image

问题解析:

首先,为什么会执行两次 useEffect

下面是官网给的解释

image

为什么 count 值最终不会再累加?

  useEffect(() => {
    // 闭包环境
    setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => {clearInterval(timer);}
  }, []);

这是因为 setInterval 是一个异步函数,useEffect 回调函数形成了一个闭包环境,所以,count 值每次获取的值,都是外层作用域 创建时保留的 count 原始值: 0。

因此,count 最终结果只会是1,不会进行累加。

传送门

github 相关 issue

衍生题型

let i = 0;
const Test = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setInterval(() => {
      setCount(count => count+1);
    }, 1000);
  }, []);

  console.log(`${++i} - ${count}`);
  return <span>{`${i} - ${count}`}</span>;
};
function App() {
  return (
    <Test/>
  );
}

@robbiemie
Copy link
Owner Author

robbiemie commented Mar 9, 2024

Q: 一个列表组件,其内部拥有state,内容为一个数组,当往数据的开头位置插入一条数据,父子组件将会发生什么

A: 在React中,当你在一个列表组件的内部状态(即一个数组)的开头位置插入一条数据时,这个更新会触发一系列的事件,影响到组件的渲染和行为。

具体包括:

1. 状态更新

首先,你会通过某种方式(比如使用setState方法)更新组件的内部状态。这个更新会将新数据插入数组的开头。

2. 重新渲染

状态的更新会导致组件重新渲染。React会对比新旧状态,来决定哪些部分需要更新。如果你使用了诸如map这样的方法来渲染列表,并且你没有为列表的每个项目指定唯一的key属性,那么插入新数据可能会导致整个列表重新渲染,而不仅仅是添加一个新项目。这可能会影响性能,尤其是在列表很长的时候。

3. key属性的重要性

为了优化性能,React推荐在渲染列表时为每个列表项指定一个唯一的key属性。如果你为列表项正确地指定了唯一的key,React能够更智能地处理这种数组更新——仅对变化的部分进行重新渲染。这意味着,只有新添加的项目会被渲染,而已经存在的列表项可以被保留,从而提高性能。

4. 父子组件的交互:

如果列表组件是一个子组件,当其内部状态更新时,它本身会重新渲染,但它不会自动导致其父组件重新渲染。父组件的重新渲染依赖于其自身状态的变化或其接收的props的变化。如果你需要父组件基于子组件状态的变化而更新,你可以通过回调函数等方式来实现这种通信。

5. 性能考量

插入数据到数组的开头通常比追加到末尾更昂贵,因为它可能涉及到移动已有数据以腾出空间。在React的上下文中,这可能影响到列表渲染的性能,特别是如果你没有正确使用key属性,或者列表很长时。优化这种情况的一个方法是确保使用有效的key属性,并且仅当必要时更新组件状态。

6. Hooks的使用

如果你使用的是函数组件,你可能会用到useState或useReducer这样的Hooks来管理状态。使用这些Hooks时,更新数组状态的原则和类组件中的setState方法相同,但语法上更简洁。

@robbiemie
Copy link
Owner Author

Q: 编写一个 名为 Message 的 react 弹窗提示组件, 要求

  1. 用 Flex 布局 + rem 实现弹窗样式,弹窗大小 400*300 , 垂直水平居中,背景蒙层黑色透明度 30%
  2. 可以将给定的提示文案中的占位符替换成按钮组件<Button />并展示,假设数据已由接口返回,通过 props 传入, 且数据结构为:
    {
    tips: "操作成功!你可以 {$2} 或者 {$1}.",
    buttons:[{
      "text": "重试"
   	 },{
      "text": "退出"
     }, {
      "text": "继续"
    }]
  }
  1. 可以将props 传入的数据被转化成相应的 UI, 如上面的数据结构会被转换成
 <div>操作成功!你可以<Button text="继续" />或者<Button text="退出" /></div>


A: 答案

```jsx
import react from 'react'

// 创建一个 button 组件
export const Button = ({ text, onClick }) => {
  return <button style={{margin: '0 0.5rem'}} onClick={onClick}>{text}</button>
}

const styleContainer = {
  position: 'fixed',
  top: '50%',
  left: '50%',
  transform: 'translate(-50%, -50%)',
  width: '25rem', // 400px
  height: '18.75rem', // 300px
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  backgroundColor: '#fff',
  borderRadius: '0.5rem',
  zIndex: 1000
}

const styleMask = {
  position: 'fixed',
  top: 0,
  left: 0,
  width: '100vw',
  height: '100vh',
  backgroundColor: 'rgba(0, 0, 0, 0.3)',
  zIndex: -1,
}

// 实现 Message 组件
export const Message = ({tips, buttons}) => {

  function renderMessage() {
    const tips = "操作成功!你可以 {$2} 或者 {$1}."
    const regex = /(\{\$\d+\})/g;
    const parts = tips.split(regex); // 文本分割
    const elem = parts.map(item => {
      if(item.match(regex)) {
        const index = +item.replace(/\D+/g, ''); // 获取下标位置
        const button = buttons[index - 1];
        return button
      }
      return item
    })
    return <div key={elem.text}>{elem.text}</div>
  }

  return (<div style={styleContainer}>
    <div style={styleMask}></div>
    <div>
      {renderMessage()}
    </div>
  </div>)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant