react模式(模式的定义,我认为是类似于一种规范,一种方法,你可以用其他的方法去实现,但这些是已有的,总结的,相对使用可靠方便的方法)
借鉴于在网上的react模式,我觉得按照模式编程会事半功倍,因此总结如下:
### 函数组件 (Function component)
函数组件 是最简单的一种声明可复用组件的方法
他们就是一些简单的函数。
```jsx
function Greeting() {
return <div>Hi there!</div>;
}
从第一个形参中获取属性集 (props)
function Greeting(props) {
return <div>Hi {props.name}!</div>;
}
```
按自己的需要可以在函数组件中定义任意变量
最后一定要返回你的 React 组件。
```jsx
function Greeting(props) {
let style = {
fontWeight: "bold",
color: context.color
};
return <div style={style}>Hi {props.name}!</div>;
}
```
使用 defaultProps 为任意必有属性设置默认值
```jsx
function Greeting(props) {
return <div>Hi {props.name}!</div>;
}
Greeting.defaultProps = {
name: "Guest"
};
```
个人总结:最简单的可复用组件,例如你想用某个小部分写成组件时,可以不必新建页面,而直接使用函数组件将会明了简单的多
### 属性解构 (Destructuring props)
解构赋值 是一种 JavaScript 特性。
出自 ES2015 版的 JavaScript 新规范。
所以看起来可能并不常见。
好比字面量赋值的反转形式。
```
let person = { name: "chantastic" };
let { name } = person;
```
同样适用于数组。
```
let things = ["one", "two"];
let [first, second] = things;
```
解构赋值被用在很多 函数组件 中。
下面声明的这些组件是相同的。
```jsx
function Greeting(props) {
return <div>Hi {props.name}!</div>;
}
function Greeting({ name }) {
return <div>Hi {name}!</div>;
}
```
有一种语法可以在对象中收集剩余属性。
叫做 剩余参数,看起来就像这样。
```jsx
function Greeting({ name, ...restProps }) {
return <div>Hi {name}!</div>;
}
```
那三个点 (...) 会把所有的剩余属性分配给 restProps 对象
然而,你能使用 restProps 做些什么呢?
继续往下看...
个人总结:了解let arr={}; let {elements} =arr;将会取出arr.elements即为解构赋值,加上大括号即可,另外了解(...)以及剩余属性restProps 对象
### JSX 中的属性展开 (JSX spread attributes)
属性展开是 JSX 中的一个的特性。
它是一种语法,专门用来把对象上的属性转换成 JSX 中的属性
参考上面的 属性解构,
我们可以 扩散 restProps 对象的所有属性到 div 元素上
```jsx
function Greeting({ name, ...restProps }) {
return <div {...restProps}>Hi {name}!</div>;
}
```
这让 Gretting 组件变得非常灵活。
我们可以通过传给 Gretting 组件 DOM 属性并确定这些属性一定会被传到 div 上
<Greeting name="Fancy pants" className="fancy-greeting" id="user-greeting" />
避免传递非 DOM 属性到组件上。 解构赋值是如此的受欢迎,是因为它可以分离 组件特定的属性 和 DOM/平台特定属性
```jsx
function Greeting({ name, ...platformProps }) {
return <div {...platformProps}>Hi {name}!</div>;
}
```
个人总结:JSX 中的属性展开会使对象的属性像数组一样展开
### 合并解构属性和其它值 (Merge destructured props with other values)
组件就是一种抽象。
好的抽象是可以扩展的。
比如说下面这个组件使用 class 属性来给按钮添加样式。
```jsx
function MyButton(props) {
return <button className="btn" {...props} />;
}
```
一般情况下这样做就够了,除非我们需要扩展其它的样式类
`<MyButton className="delete-btn">Delete...</MyButton>`
在这个例子中把 btn 替换成 delete-btn
JSX 中的属性展开 对先后顺序是敏感的
扩散属性中的 className 会覆盖组件上的 className。
我们可以改变它两的顺序,但是目前来说 className 只有 btn。
```
function MyButton(props) {
return <button {...props} className="btn" />;
}
```
我们需要使用解构赋值来合并入参 props 中的 className 和基础的(组件中的) className。 可以通过把所有的值放在一个数组里面,然后使用一个空格连接它们。
```jsx
function MyButton({ className, ...props }) {
let classNames = ["btn", className].join(" ");
return <button className={classNames} {...props} />;
}
为了保证 undefined 不被显示在 className 上,可以使用 默认值。
function MyButton({ className = "", ...props }) {
let classNames = ["btn", className].join(" ");
return <button className={classNames} {...props} />;
}
```
个人总结:可以写组件时很好的用到该功能,比如写完利用该功能某些组件,可以对 该组件设置classname以达到自定义组件样式的问题,而不需要知道该组件到底有哪些固定样式等等,可以很好地解决一些兼容性的问题,比如button的一些组件,除非我看完其组件的源代码,否则无法知道如何将其改为红色,或者别的颜色
### 条件渲染 (Conditional rendering)
不可以在一个组件声明中使用 if/else 语句 You can't use if/else statements inside a component declarations.
所以可以使用 条件(三元)运算符 和 短路计算。
```jsx
如果
{
condition && <span>Rendered when `truthy`</span>;
}
除非
{
condition || <span>Rendered when `falsy`</span>;
}
如果-否则
{
condition ? (
<span>Rendered when `truthy`</span>
) : (
<span>Rendered when `falsy`</span>
);
}
```
个人总结:这一点在react中经常用到,render方法里面写jsx常常为难一些条件判断是否展示该dom ,或者是展示哪个dom时,该模式可以巧妙解决
### 子元素类型 (Children types)
很多类型都可以做为 React 的子元素。
多数情况下会是 数组 或者 字符串。
### 字符串 String
`<div> Hello World! </div>`
个人:字符串将会直接展示
### 数组 Array
`<div>{["Hello ", <span>World</span>, "!"]}</div>`
个人:数组在jsx将会展开,该结果应该展示为`<div>Hello <span> world </span> !</div>`
### 数组做为子元素 (Array as children)
将数组做为子元素是很常见的。
列表是如何在 React 中被绘制的。
我们使用 map() 方法创建一个新的 React 元素数组
```jsx
<ul>
{["first", "second"].map(item => (
<li>{item}</li>
))}
</ul>
这和使用字面量数组是一样的。
<ul>{[<li>first</li>, <li>second</li>]}</ul>
这个模式可以联合解构、JSX 属性扩散以及其它组件一起使用,看起来简洁无比
<ul>
{arrayOfMessageObjects.map(({ id, ...message }) => (
<Message key={id} {...message} />
))}
</ul>
```
个人:当jsx中需要遍历生成dom时经常使用数组map生成dom数组,也可以直接使用字面量数组,相对简洁
### 函数做为子元素 (Function as children)
React 组件不支持函数类型的子元素。
然而 渲染属性 是一种可以创建组件并以函数作为子元素的模式。
### 渲染属性 (Render prop)
这里有个组件,使用了一个渲染回调函数 children。
这样写并没有什么用,但是可以做为入门的简单例子。
const Width = ({ children }) => children(500);
组件把 children 做为函数调用,同时还可以传一些参数。上面这个 500 就是实参。
为了使用这个组件,我们可以在调用组件的时候传入一个子元素,这个子元素就是一个函数。
<Width>{width => <div>window is {width}</div>}</Width>
我们可以得到下面的输出。
<div>window is 500</div>
有了这个组件,我们就可以用它来做渲染策略。
<Width>
{width => (width > 600 ? <div>min-width requirement met!</div> : null)}
</Width>
如果有更复杂的条件判断,我们可以使用这个组件来封装另外一个新组件来利用原来的逻辑。
const MinWidth = ({ width: minWidth, children }) => (
<Width>{width => (width > minWidth ? children : null)}</Width>
);
显然,一个静态的 Width 组件并没有什么用处,但是给它绑定一些浏览器事件就不一样了。下面有个实现的例子。
```jsx
class WindowWidth extends React.Component {
constructor() {
super();
this.state = { width: 0 };
}
componentDidMount() {
this.setState(
{ width: window.innerWidth },
window.addEventListener("resize", ({ target }) =>
this.setState({ width: target.innerWidth })
)
);
}
render() {
return this.props.children(this.state.width);
}
}
```
许多开发人员都喜欢 高阶组件 来实现这种功能。但这只是个人喜好问题。
个人总结:这两点不是很清楚 请教一下别人