轉眼,從接觸react到如今,有一年多的時間了. 從一開始cv,學習語法,到如今本身寫功能組件,封裝. 分享一些心得.java
react中組件的開始.先分析下這個react
//生命週期的接口
interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> { }
class Component<P, S> {
//構造函數
constructor(props: Readonly<P>);
constructor(props: P, context?: any);
//咱們更新組件的setState
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
forceUpdate(callBack?: () => void): void;
//組件的邏輯
render(): ReactNode;
readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>;
//state對象
state: Readonly<S>;
context: any;
//組件引用
refs: {
[key: string]: ReactInstance
};
}
複製代碼
日常寫組件,經常使用到的就4個es6
render
state
setState
refs
bash
有人會說,還有constructor
呢.antd
實際上,我這個幾乎沒用到.app
早期的react,常規應該是這樣的:函數
state的定義,函數的定義,都在constructor裏面. 如今依然看到許多人這樣寫.其實也沒啥毛病.oop
但我以爲react,JSX,es6不錯的地方.都讓js更像編譯語言,而不是腳本語言. 說直接點.很是像java之類的語言學習
做爲一個寫了幾年java的人,我我的以爲這樣看起來舒服不少.哈哈.ui
這個標誌也是繼承,複寫的意思.
其實無論什麼語言, 開發設計都應該遵循六大設計原則:
單一職責原則(SRP):一個組件只作一件事
里氏替換原則(LSP): 繼承
依賴倒轉原則(DIP):多態
接口隔離原則(ISP):不要濫用接口(別繼承沒用的)
迪米特法則(LOD): 耦合
開閉原則(OCP):擴展性強(邏輯寫好了別瞎JB改.要讓人能擴展)
原理並不難,但真的要作好,仍是很須要技術的(廢話).
單一職責原則
里氏替換原則
開閉原則
從我在交流羣,還有看到的代碼來講,包括我本身. 這3個是最經常使用,卻最容易被忽略.
不扯犢子了.
首先,想好一個需求(單一指責),儘可能不要太複雜.不要想太多.
1.間隔時間
2.當前展現內容(單個,或者多個)
3.開始,暫停
每次切換的回調
/**
* 定時切換
*/
class Test extends Component {
state = {
};
render() {
const { time, open, children } = this.props;
return (
<div>
</div>
);
}
}
Test.propTypes = {
// 間隔時間
time: PropTypes.number,
// 是否啓動
open: PropTypes.bool,
};
export default Test;
複製代碼
有人會問,爲何展現內容的參數沒定義.
這就涉及react中.children
這個參數了.
也就是咱們封裝的組件下,包含的組件,就會在這個children
裏面 debug看一下
因此展現內容,就不須要特地再去寫一個參數了. 初始化
componentDidMount() {
this.notifyContent();
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.children !== prevProps.children) {
this.notifyContent();
}
}
notifyContent = () => {
const { children } = this.props;
const content = Array.isArray(children) ? children : [children];
this.setState({
content,
});
};
複製代碼
這裏就用setTimeout遞歸寫了.
componentDidMount() {
this.loop();
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.open !== prevProps.open) {
this.loop();
}
}
loop = () => {
const { time = 1000, open = false } = this.props;
//若是沒開就關閉
if (!open) {
return;
}
setTimeout(() => {
const { content, index } = this.state;
const newIndex = index + 1;
this.setState({
index: newIndex >= content.length ? 0 : newIndex
});
this.loop();
}, time);
};
複製代碼
把loop改造一下,中間添加change方法
loop = () => {
const { time = 1000, open = false } = this.props;
if (!open) {
return;
}
setTimeout(() => {
const { content, index } = this.state;
this.change(index, content[index]);
const newIndex = index + 1;
this.setState({
index: newIndex >= content.length ? 0 : newIndex
});
this.loop();
}, time);
};
change = (index, content) => {
const { onChange, change } = this.props;
if (onChange) { //antd的form表單,默認會設置.
onChange(index, content);
}
if (change) {//因此通常寫2個.
change(index, content);
}
};
複製代碼
getItem = (index) => {
const { wrapper } = this.props;
const item = this.state.content[index];
if (wrapper) {
return wrapper(item, index);
}
return item;
};
複製代碼
import React, { Component } from 'react';
import PropTypes from 'prop-types';
/**
* 定時切換
*/
class Test extends Component {
state = {
index: 0,
content: [],
};
componentDidMount() {
this.notifyContent();
this.loop();
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.open !== prevProps.open) {
this.loop();
}
if (this.props.children !== prevProps.children) {
this.notifyContent();
}
}
//更新,保存主內容引用
notifyContent = () => {
const { children } = this.props;
const content = Array.isArray(children) ? children : [children];
this.setState({
content,
});
};
// 定時循環
loop = () => {
const { time = 1000, open = false } = this.props;
if (!open) {
return;
}
setTimeout(() => {
const { content, index } = this.state;
this.change(index, content[index]);
const newIndex = index + 1;
this.setState({
index: newIndex >= content.length ? 0 : newIndex
});
this.loop();
}, time);
};
// 改變回調
change = (index, content) => {
const { onChange, change } = this.props;
if (onChange) { //antd的form表單,默認會設置.
onChange(index, content);
}
if (change) {//因此通常寫2個.
change(index, content);
}
};
// 獲取展現內容
getItem = (index) => {
const { wrapper } = this.props;
const item = this.state.content[index];
if (wrapper) {
return wrapper(item, index);
}
return item;
};
render() {
const { index } = this.state;
return (
<div>
{this.getItem(index)}
</div>
);
}
}
Test.propTypes = {
time: PropTypes.number,
open: PropTypes.bool,
wrapper: PropTypes.func,
change: PropTypes.func,
};
export default Test;
複製代碼
<Test
open={true}
time={5000}
change={(i, item) => {
console.log(i, item);
}}>
<p>1</p>
<p>2</p>
<p>3</p>
</Test>
複製代碼
是否是很簡單.
propTypes是個好東西,必定要用 (若是你想讓的你代碼好維護的話)
效果就不貼了,作gif有點費事,有興趣直接複製跑一下就完了.
歡迎你們點贊,留言交流