That's true, Sitecore components are useful and provide lots of facilities. They allow to build fully flexible website. And there is not much problem using post-backs to display your contents. However, if your website has user interactions, then it could be a headache. Too many post-backs would occur a poor user experience.
That's why client-side technologies are really powerful and popular for a long time. There are plenty of javascript libraries and frameworks which all try to provide better user experience in different ways.
It is not a topic of this article why I chose React. There are some good articles about it (e.g. Jonne Kats' great article). However, one of the reasons is React only focus on view part. It is not a fully framework like Angular, it is rich featured library instead. And that's what I was looking for! The idea was to benefit Sitecore server-side and React client-side power. It seems they are very good match!
Let's dive into code...
I've implemented a simple product list page with React. It's simple but after understanding the implementation logic, then, it can easily be extended. The idea was adding a Sitecore component as usual but giving all responsibility to React components inside Sitecore component. I will show implementation details later in this article.
But before going implementation details, I want to show final result here.
Let's add necessary libraries first.
I've used ReactJS.Net packages, I recommend to have a look at documentation first. It's clear and easy to use. I don't give details how to configure things, they are already explained well in documentation.
Once you finish reading, you can install React.Web.Mvc4 and System.Web.Optimization.React packages via nuget:
Nothing special with adding controller and view. I've created Product controller and ProductList partial view. They looks like this:
Four React components were added:
ProductList is straight forward and only responsible to display products. There is no user interaction on it.
ProductCategoryList has checkbox selection events and they are handled as below. The important thing here is after each selection, we pass selected categories with a function to parent component which is ProductListWrapper. See the line marked as red below.
When new category selection array pass to "onCategoryChanged" function, it is handled in ProductListWrapper like this:
Same logic is used for pagination. Selected categories are already stored in state and we just need new page index when click the page buttons:
That's why client-side technologies are really powerful and popular for a long time. There are plenty of javascript libraries and frameworks which all try to provide better user experience in different ways.
It is not a topic of this article why I chose React. There are some good articles about it (e.g. Jonne Kats' great article). However, one of the reasons is React only focus on view part. It is not a fully framework like Angular, it is rich featured library instead. And that's what I was looking for! The idea was to benefit Sitecore server-side and React client-side power. It seems they are very good match!
Let's dive into code...
I've implemented a simple product list page with React. It's simple but after understanding the implementation logic, then, it can easily be extended. The idea was adding a Sitecore component as usual but giving all responsibility to React components inside Sitecore component. I will show implementation details later in this article.
But before going implementation details, I want to show final result here.
Let's add necessary libraries first.
I've used ReactJS.Net packages, I recommend to have a look at documentation first. It's clear and easy to use. I don't give details how to configure things, they are already explained well in documentation.
Once you finish reading, you can install React.Web.Mvc4 and System.Web.Optimization.React packages via nuget:
Adding Sitecore Component
I've added a page item to list products and added a controller rendering as usual.Nothing special with adding controller and view. I've created Product controller and ProductList partial view. They looks like this:
public class ProductController : BaseController { private readonly IProductRetrieveService _productRetrieveService; public ProductController(IProductRetrieveService productRetrieveService) { _productRetrieveService = productRetrieveService; } public PartialViewResult ProductList() { var model = _productRetrieveService.GetProducts((base.DataSourceItem?.ID?.Guid).Value); return PartialView(model); }
Working with React Components
Special part is in ProductList component. Here, we give all responsibility to React. We only need to do is providing initial data to React component.@model Training3.Data.ViewModels.Web.Product.ProductListViewModel @Html.React("ProductListWrapper", new { initialData = Model })
Four React components were added:
ProductListWrapper
includes other components. I've set state while initializing ProductListWrapper
class. Then, necessary data were passed to sub components as seen image below:
ProductList is straight forward and only responsible to display products. There is no user interaction on it.
class ProductList extends React.Component { render() { const products = this.props.data.map(product => ( <div className="col-md-4" key={product.Id}> <img src={product.Image.Src} width="200" height="250" /> <p>{product.Name}</p> </div> )); return ( <div className="row"> <div className="col-md-12"> <h5>Product List <span className="pull-right">{this.props.pageInfo.TotalRecordCount} products found</span></h5> </div> {products} </div> ); } }
ProductCategoryList has checkbox selection events and they are handled as below. The important thing here is after each selection, we pass selected categories with a function to parent component which is ProductListWrapper. See the line marked as red below.
class ProductCategoryList extends React.Component { componentWillMount() { this.selectedCheckboxes = new Set(); } toggleCheckboxChange = (catId) => { console.log("Cat Id: " + catId); if (this.selectedCheckboxes.has(catId)) { this.selectedCheckboxes.delete(catId); } else { this.selectedCheckboxes.add(catId); } this.props.onCategoryChanged(Array.from(this.selectedCheckboxes)); } render() { const categories = this.props.data.map(cat => ( <li className="list-group-item" key={cat.Id}><input type="checkbox" onChange={() => this.toggleCheckboxChange(cat.Id)} /> {cat.Name}</li> )); return ( <div> <h5>Product Category List</h5> <ul className="list-group"> {categories} </ul> </div> ); } }
When new category selection array pass to "onCategoryChanged" function, it is handled in ProductListWrapper like this:
Same logic is used for pagination. Selected categories are already stored in state and we just need new page index when click the page buttons:
handlePageChange(pageIndex) { this.loadProducts(this.state.selectedCategories, pageIndex); }
That's it! It is flexible and you can configure components and actions how you want.I haven't worked with React before, this example was the first time for me. I can say that I really liked React and also impressed the power to combine it with Sitecore.
Comments
Post a Comment