响应式系统与 React| 青训营笔记

95 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天

重点内容:

  1. React历史与应用
  2. React的设计思路
  3. hooks写法
  4. React的实现

详细知识点:

一、React历史与应用

  • 前端应用开发,如Facebook,Instagram,Netflix网页版
  • 移动原生应用开发,如Instagram,Discord,Oculus
  • 结合Electron,进行桌面应用开发

二、React的设计思路

原生JS VS React:

76d5e0c8a49459a2b5c637b83678af4.jpg

响应式 VS 转换式系统
转化式系统:给定“输入”求解“输出”
响应式系统:监听事件,消息驱动

  1. 状态更新,UI自动更新
  2. 前端代码组件化,可复用,可封装
  3. 状态之间的互相依赖关系,只需声明即可

组件化

  1. 组件是组件的组合/原子组件
  2. 组件内拥有状态,外部不可见
  3. 父组件可将状态传入组件内部

组件设计

  1. 组件声明了状态和UI的映射
  2. 组件又Props/State两种状态
  3. “组件”可由其他组件拼装而成

生命周期

  1. 组件从创建到死亡它会经历一些特定阶段
  2. React组件中包含一系列钩子函数(生命周期回调函数),会在特定的时刻调用
  3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作
    *生命周期钩子运行顺序跟写代码的顺序无关

三、React(hooks)的写法

  • useState:传入一个初始值,返回一个状态,和set该状态的函数,用户可以通过调用该函数,来实现状态的修改
  • useEffect:传入一个函数,和一个数组,数组是状态的数组,称作依赖项,该函数在mount时,和依赖项被set的时候会执行 *不要在循环,条件或嵌套函数中调用Hook

四、React的实现

Virtual DOM(虚拟DOM)

  1. 本质是object类型对象(一般类型对象)
  2. 虚拟DOM属性少,真实DOM属性多(因为虚拟DOM是React内部在用,无需真实DOM上那么多属性)
  3. 虚拟DOM最终会被React转化为真实DOM,呈现在页面上

Diffing 算法

对同一层次的节点进行比较。算法核心:复用

  • 旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
  1. 若虚拟 DOM 中内容没变,直接使用之前的真实 DOM 。
  2. 若虚拟 DOM 中内容变了,则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM。
  • 旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key:
  1. 根据数据创建新的真实 DOM ,随后渲染到到页面。

练习:

效果:

du9y4-0dlaa.gif

代码:

App.jsx:

function App() {
  // Add recipe object 
  const initialRecipe = { 
    title: 'mashed potatoes', 
    feedback: { 
      rating: 4.8, 
      reviews: 2.0
    },
    ingredients : [
      { name : '3 potatoes, cut into 1/2" pieces', prepared: false},
      { name: '4 Tbsp butter', prepared: false}, 
      { name: '1/8 cup heavy cream', prepared: false}, 
      { name: 'Salt', prepared: true}, 
      { name: 'pepper', prepared: true}, 
    ],
    steps: [
      "Add cut potatoes to a pot of heavily salted water. " , 
      "Bring pot to a boil . " , 
      "Boil the potatoes until fork tender, about 15-20 minutes.",
      "strain the potatoes. ", 
      "Return potatoes to pot. " , 
      "Add butter, cream, salt, and pepper to taste." , 
      "Mash potatoes. " , 
      "Reseason and add butter and cream as desired." 
    ],
  };

  const [ recipe, setRecipe ] = useState(initialRecipe);
  const [ prepared, setPrepared ] = useState(false);

  // Create ingredientClick event listener
  function ingredientClick(index) {
    const updatedRecipe = { ...recipe };
    updatedRecipe.ingredients[index].prepared = !updatedRecipe.ingredients[index].prepared;
    setRecipe(updatedRecipe);
  }
  useEffect(() => {
      setPrepared(recipe.ingredients.every(i => i.prepared));
  }, [recipe]);

  return ( 
    <article> 
      <h1>Recipe Manager</h1>
        <RecipeTitle title={recipe.title} feedback={recipe.feedback} />
        <IngredientList ingredients={recipe.ingredients} onClick={ ingredientClick } />
        { prepared ? <h2>Prep work done!</h2> : <h2>Just keep chopping</h2>}
        <RecipeStep steps = {recipe.steps}/>
    </article>
  )
}

App.css:

article {
  margin-left: 10%;
  margin-right: 10%;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  font-size: 18px;
}

RecipeTitle.jsx:

function RecipeStep(props){
  //Create the list items using map
  const stepItems = props.steps.map((steps, index) => {
    return (
      // Return the desired HTML for each ingredient
      <li key={index}>
        {steps}
      </li>
    );
  });
  return (
    <section>
      <h3>Step:</h3>
      <ol>
        {stepItems}
      </ol>
    </section>
  )

}

RecipeTitle.css

.red {
    color: red;
}
.green {
    color: green;
}

IngredientList.jsx:

function IngredientList(props) {
    // Create the list items using map
    const ingredientListItems = props.ingredients.map((ingredient, index) => {
        return (
            // Return the desired HTML for each ingredient
            <li key={index} 
                className={ ingredient.prepared ? 'prepared' : '' }
                // Add onClick event
                onClick={ () => props.onClick(index) }
            >
                { ingredient.name }
            </li>
        );
    });
    return (
        <ul>
            { ingredientListItems }
        </ul>
    );
}

IngredientList.css

.prepared {
    text-decoration: line-through;
}

RecipeStep.jsx

function RecipeStep(props){
  //Create the list items using map
  const stepItems = props.steps.map((steps, index) => {
    return (
      // Return the desired HTML for each ingredient
      <li key={index}>
        {steps}
      </li>
    );
  });
  return (
    <section>
      <h3>Step:</h3>
      <ol>
        {stepItems}
      </ol>
    </section>
  )
}