背景
之前面大厂遇到这个面试题, 现在有空理一下思路, 顺下写下我的实现
hooks版本
思路: 使用自定义hooks抽取状态
const defaultState = {
status: 'idle', // 状态值: 初始 | 加载中 | 错误 | 成功
data: null,
error: null,
}
const useFetch = (initialState) => {
const [state, setState] = useState({
...defaultState,
...initialState,
});
const setData = (data) => {
setState({
data,
status: 'success',
error: null,
})
};
const setError = (error) => {
setState({
error,
status: 'error',
data: null,
})
};
// 这里run传入的参数为promise(调取接口的方法)
const run = (promise) => {
if(!promise || !promise.then) {
throw new Error('请传入Promise类型')
}
setState({ ...state, status: 'loading' })
return promise.then(data => {
setData(data)
return data;
}).catch(err => {
setError(err)
return err
})
}
return {
isIdle: state.status === 'idle',
isLoading: state.status === 'loading',
isError: state.status === 'error',
isSuccess: state.status === 'success',
run,
setData,
setError,
...state,
}
}
class版本
思路:利用高阶组件的render props component(增强组件props)
class Fetcher extends React.Component {
constructor(props) {
super(props)
this.state = {
data: null,
status: 'idle'
error: null
}
}
componentDidMount() {
this.setState({ status: 'loading' })
fetch(this.props.url) // children组件传进来的url
.then(res => {
this.setState({
data: res,
status: 'success',
error: null,
})
})
.catch(error => {
this.setState({
error,
status: 'error',
data: null
})
})
}
render() {
const renderProps = {
isIdle: this.state.status === 'idle',
isLoading: this.state.status === 'loading',
isError: this.state.status === 'error',
isSuccess: this.state.status === 'success',
...this.state,
}
return this.props.children(renderProps)
}
}
使用
const MyComponent = () => {
<Fetcher url={xxxxxxx}>
{({ data, error, isLoading, isError, ...rest }) => {
if(isError) {
return <div>{error}</div>
}
if(isLoading) {
return <div>loading...</div>
}
if(!data) {
return <div>No Data</div>
}
return (
<div>{data}</div>
)
}
}
</Fetcher>
}