这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
重点内容:
- React历史与应用
- React的设计思路
- hooks写法
- React的实现
详细知识点:
一、React历史与应用
- 前端应用开发,如Facebook,Instagram,Netflix网页版
- 移动原生应用开发,如Instagram,Discord,Oculus
- 结合Electron,进行桌面应用开发
二、React的设计思路
原生JS VS React:
响应式 VS 转换式系统:
转化式系统:给定“输入”求解“输出”
响应式系统:监听事件,消息驱动
- 状态更新,UI自动更新
- 前端代码组件化,可复用,可封装
- 状态之间的互相依赖关系,只需声明即可
组件化:
- 组件是组件的组合/原子组件
- 组件内拥有状态,外部不可见
- 父组件可将状态传入组件内部
组件设计:
- 组件声明了状态和UI的映射
- 组件又Props/State两种状态
- “组件”可由其他组件拼装而成
生命周期:
- 组件从创建到死亡它会经历一些特定阶段
- React组件中包含一系列钩子函数(生命周期回调函数),会在特定的时刻调用
- 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作
*生命周期钩子运行顺序跟写代码的顺序无关
三、React(hooks)的写法
- useState:传入一个初始值,返回一个状态,和set该状态的函数,用户可以通过调用该函数,来实现状态的修改
- useEffect:传入一个函数,和一个数组,数组是状态的数组,称作依赖项,该函数在mount时,和依赖项被set的时候会执行 *不要在循环,条件或嵌套函数中调用Hook
四、React的实现
Virtual DOM(虚拟DOM)
- 本质是object类型对象(一般类型对象)
- 虚拟DOM属性少,真实DOM属性多(因为虚拟DOM是React内部在用,无需真实DOM上那么多属性)
- 虚拟DOM最终会被React转化为真实DOM,呈现在页面上
Diffing 算法
对同一层次的节点进行比较。算法核心:复用
- 旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
- 若虚拟 DOM 中内容没变,直接使用之前的真实 DOM 。
- 若虚拟 DOM 中内容变了,则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM。
- 旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key:
- 根据数据创建新的真实 DOM ,随后渲染到到页面。
练习:
效果:
代码:
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>
)
}