Last active
July 14, 2017 15:33
-
-
Save lijunle/6b0cc2538b66c36250f42f32baec2e73 to your computer and use it in GitHub Desktop.
React with MVC - https://codepen.io/lijunle/pen/BZbZaq
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @file App.tsx */ | |
class App extends React.PureComponent { | |
constructor(props) { | |
super(props); | |
this.state = { | |
mount: true | |
}; | |
} | |
render() { | |
return ( | |
<div> | |
{ | |
this.state.mount && ( | |
<MVC | |
model={{ count: 0 }} | |
view={MyView} | |
controller={MyController} | |
/> | |
) | |
} | |
<button onClick={() => this.setState({ mount: true })}> | |
Mount | |
</button> | |
<button onClick={() => this.setState({ mount: false })}> | |
Unmount | |
</button> | |
</div> | |
) | |
} | |
} | |
ReactDOM.render(<App />, document.getElementById(('app'))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @file BaseCollection.ts */ | |
class BaseController<T> { | |
protected setState: (callback: (prevState: T) => T) => void; | |
constructor(setState) { | |
this.setState = setState; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @file MVC.ts */ | |
interface IMVCProps<TModel, TView, TController> { | |
model: TModel; | |
view: TView; | |
controller: TController; | |
} | |
class MVC<TModel, TView, TController> | |
extends React.PureComponent<IMVCProps<TModel, TView, TController>, TModel> { | |
private mounted = false; | |
constructor(props) { | |
super(props); | |
this.state = props.model; | |
const setState = this.setState; | |
this.setState = (prevState) => { | |
if (this.mounted) { | |
setState.call(this, prevState); | |
} | |
} | |
this.controller = new (props.controller)(this.setState); | |
Object.getOwnPropertyNames(Object.getPrototypeOf(this.controller)).forEach((key) => { | |
if (key === 'constructor') { return; } | |
this.controller[key] = this.controller[key].bind(this.controller); | |
}); | |
} | |
componentDidMount() { | |
this.mounted = true; | |
} | |
componentWillUnmount() { | |
this.mounted = false; | |
} | |
render() { | |
return React.createElement(this.props.view, { | |
controller: this.controller, | |
...this.state | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @file MyController.ts */ | |
class MyController extends BaseController<MyModel> { | |
public inc(step: number) { | |
return () => this.setState(state => ({ count: state.count + step })); | |
} | |
public dec() { | |
this.setState(state => ({ count: state.count - 1 })); | |
} | |
public deferInc() { | |
setTimeout(() => { | |
this.setState(state => ({ count: state.count + 10 })) | |
}, 1000) | |
} | |
public deferDec() { | |
setTimeout(() => { | |
this.setState(state => ({ count: state.count - 10 })) | |
}, 3000) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @file MyModel.ts */ | |
interface MyModel { | |
count: number; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @file MyView.tsx */ | |
const MyView = ({ controller, count }: MyModel & { controller: MyController }) => { | |
return ( | |
<div> | |
<button onClick={controller.inc(1)}>Inc</button> | |
<button onClick={controller.deferInc}>Defer Inc</button> | |
<div>{count}</div> | |
<button onClick={controller.dec}>Dec</button> | |
<button onClick={controller.deferDec}>Defer Dec</button> | |
</div> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment